using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using Microsoft.SharePoint;
using Microsoft.Office.Server.Search.Query;
using Microsoft.Office.Server.Search.WebControls;
using System.Xml;
using System.Diagnostics;
using System.Web.Configuration;

namespace CKS.EBE.Search
{
    public abstract class SearchResults : CKS.EBE.WebControls.XmlBasedControl
    {
        private string _queryParameter = "k";
        private XmlDocument _resultsXml;
        private int _resultsPerPage = 10;
        private int _exactMinimum = 100;
        private string _pageParameter = "Page";
        private ResultType _resultTypes = ResultType.RelevantResults;
        private bool _enableStemming = true;
        private int _rowLimit = -1;
        private bool _trimDuplicates = false;

        public bool TrimDuplicates
        {
            get { return _trimDuplicates; }
            set { _trimDuplicates = value; }
        }

        public int RowLimit
        {
            get { return (_rowLimit == -1) ? ResultsPerPage : _rowLimit; }
            set { _rowLimit = value; }
        }

        public bool EnableStemming
        {
            get { return _enableStemming; }
            set { _enableStemming = value; }
        }

        public ResultType ResultTypes
        {
            get { return _resultTypes; }
            set { _resultTypes = value; }
        }

        public string PageParameter
        {
            get { return _pageParameter; }
            set { _pageParameter = value; }
        }

        public int ExactMinimum
        {
            get { return _exactMinimum; }
            set { _exactMinimum = value; }
        }

        public int ResultsPerPage
        {
            get { return _resultsPerPage; }
            set { _resultsPerPage = value; }
        }

        public int CurrentPage
        {
            get
            {
                int page = 0;
                return (int.TryParse(HttpContext.Current.Request[PageParameter], out page)) ? page : 1;
            }
        }

        public XmlDocument ResultsXml
        {
            get { if (_resultsXml == null) { _resultsXml = new XmlDocument(); _resultsXml.LoadXml("<Results/>"); } return _resultsXml; }
        }

        public string QueryParameter
        {
            get { return _queryParameter; }
            set { _queryParameter = value; }
        }

        protected virtual Query GetQuery()
        {
            return null;
        }

        protected virtual void ModifyQuery(Query q)
        {
        }

        protected override XmlDocument BuildDocument()
        {
            try
            {
                Query q = GetQuery();
                ModifyQuery(q);

                q.TrimDuplicates = TrimDuplicates;

                q.ResultTypes = ResultTypes;
                q.RowLimit = ResultsPerPage;
                q.StartRow = (CurrentPage-1) * ResultsPerPage;
                q.EnableStemming = EnableStemming;

                if (SPSecurity.AuthenticationMode != AuthenticationMode.Windows)
                    q.AuthenticationType = QueryAuthenticationType.PluggableAuthenticatedQuery;
                else
                    q.AuthenticationType = QueryAuthenticationType.NtAuthenticatedQuery;

                ResultTableCollection r = q.Execute();

                ResultsXml.DocumentElement.SetAttribute("DatabaseTime", r.DatabaseTime.ToString());
                ResultsXml.DocumentElement.SetAttribute("ElapsedTime", r.ElapsedTime.ToString());

                AddStringArrayToXml(ResultsXml.DocumentElement, "QueryTerms", r.QueryTerms);
                AddStringArrayToXml(ResultsXml.DocumentElement, "IgnoredNoiseWords", r.IgnoredNoiseWords);

                XmlElement oSpelling = ResultsXml.CreateElement("SpellingSuggestion");
                ResultsXml.DocumentElement.AppendChild(oSpelling);
                oSpelling.InnerXml = r.SpellingSuggestion.Trim();

                foreach (ResultTable rt in r)
                    AddResults(rt);

                Transform.XslArguments.AddParam("ItemsPerPage", "", ResultsPerPage.ToString());
                Transform.XslArguments.AddParam("ResultsPerPage", "", ResultsPerPage.ToString());
                Transform.XslArguments.AddParam("EndRow", "", (CurrentPage * ResultsPerPage).ToString());
                Transform.XslArguments.AddParam("StartRow", "", ((CurrentPage * ResultsPerPage) - ResultsPerPage).ToString());

                Transform.XslArguments.AddParam("QueryParameterName", "", QueryParameter);
                Transform.XslArguments.AddParam("PageParameterName", "", PageParameter);

                return ResultsXml;
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex);
                return null;
            }
        }

        private void AddStringArrayToXml(XmlElement oParent, string elementName, string[] items)
        {
            XmlElement oItems = oParent.OwnerDocument.CreateElement(elementName);
            oParent.AppendChild(oItems);
            foreach (string s in items)
            {
                XmlElement oItem = oParent.OwnerDocument.CreateElement("Item");
                oItem.InnerXml = s;
                oItems.AppendChild(oItem);
            }
        }

        protected virtual void AddResults(ResultTable resultTable)
        {
            XmlElement oResults = ResultsXml.CreateElement(resultTable.ResultType.ToString());
            ResultsXml.DocumentElement.AppendChild(oResults);

            oResults.SetAttribute("TotalRows", resultTable.TotalRows.ToString());
            oResults.SetAttribute("IsTotalRowsExact", resultTable.IsTotalRowsExact.ToString());

            while (resultTable.Read())
            {
                XmlElement oResult = ResultsXml.CreateElement("r");
                oResults.AppendChild(oResult);
                for (int c = 0; c < resultTable.FieldCount; c++)
                    AddField(oResult, c, resultTable);
            }
        }

        private void AddField(XmlElement oResult, int c, ResultTable resultTable)
        {
            try
            {
                string sName = resultTable.GetName(c).ToUpper();
                XmlElement oField = ResultsXml.CreateElement(sName);
                if (resultTable[c] != null)
                {
                    oResult.AppendChild(oField);

                    switch (sName.ToLower())
                    {
                        case "hithighlightedsummary":
                            {
                                try
                                {
                                    oField.InnerXml = resultTable[c].ToString();
                                }
                                catch (Exception ex)
                                {
                                    Trace.WriteLine(ex);
                                    Trace.WriteLine("Failed to set inner XML for HtiHightlight: " + resultTable[c].ToString());
                                }
                                break;
                            }
                        default:
                            {
                                oField.InnerText = resultTable[c].ToString();
                                break;
                            }
                    }
                }
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex);
            }

        }
    }
}
